{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "13cd1c3e",
   "metadata": {},
   "source": [
    "[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/langchain-ai/langchain-academy/blob/main/module-1/agent-memory.ipynb) [![Open in LangChain Academy](https://cdn.prod.website-files.com/65b8cd72835ceeacd4449a53/66e9eba12c7b7688aa3dbb5e_LCA-badge-green.svg)](https://academy.langchain.com/courses/take/intro-to-langgraph/lessons/58239417-lesson-7-agent-with-memory)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "8c451ffd-a18b-4412-85fa-85186824dd03",
   "metadata": {},
   "source": [
    "# Agent memory\n",
    "\n",
    "## Review\n",
    "\n",
    "Previously, we built an agent that can:\n",
    "\n",
    "* `act` - let the model call specific tools \n",
    "* `observe` - pass the tool output back to the model \n",
    "* `reason` - let the model reason about the tool output to decide what to do next (e.g., call another tool or just respond directly)\n",
    "\n",
    "![Screenshot 2024-08-21 at 12.45.32 PM.png](https://cdn.prod.website-files.com/65b8cd72835ceeacd4449a53/66dbab7453080e6802cd1703_agent-memory1.png)\n",
    "\n",
    "## Goals\n",
    "\n",
    "Now, we're going extend our agent by introducing memory."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d2b4b45b-cbaa-41b1-b3ed-f6b0645be3f9",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%capture --no-stderr\n",
    "%pip install --quiet -U langchain_openai langchain_core langgraph langgraph-prebuilt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "2b0cfa99",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os, getpass\n",
    "\n",
    "def _set_env(var: str):\n",
    "    if not os.environ.get(var):\n",
    "        os.environ[var] = getpass.getpass(f\"{var}: \")\n",
    "\n",
    "_set_env(\"OPENAI_API_KEY\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "02eff247-a2aa-4f7a-8be1-73dfebfecc63",
   "metadata": {},
   "source": [
    "We'll use [LangSmith](https://docs.smith.langchain.com/) for [tracing](https://docs.smith.langchain.com/concepts/tracing)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "74ef2ff0",
   "metadata": {},
   "outputs": [],
   "source": [
    "_set_env(\"LANGSMITH_API_KEY\")\n",
    "os.environ[\"LANGSMITH_TRACING\"] = \"true\"\n",
    "os.environ[\"LANGSMITH_PROJECT\"] = \"langchain-academy\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9c5f123b-db5d-4816-a6a3-2e4247611512",
   "metadata": {},
   "source": [
    "This follows what we did previously."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "46647bbe-def5-4ea7-a315-1de8d97c8288",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "def multiply(a: int, b: int) -> int:\n",
    "    \"\"\"Multiply a and b.\n",
    "\n",
    "    Args:\n",
    "        a: first int\n",
    "        b: second int\n",
    "    \"\"\"\n",
    "    return a * b\n",
    "\n",
    "# This will be a tool\n",
    "def add(a: int, b: int) -> int:\n",
    "    \"\"\"Adds a and b.\n",
    "\n",
    "    Args:\n",
    "        a: first int\n",
    "        b: second int\n",
    "    \"\"\"\n",
    "    return a + b\n",
    "\n",
    "def divide(a: int, b: int) -> float:\n",
    "    \"\"\"Divide a and b.\n",
    "\n",
    "    Args:\n",
    "        a: first int\n",
    "        b: second int\n",
    "    \"\"\"\n",
    "    return a / b\n",
    "\n",
    "tools = [add, multiply, divide]\n",
    "llm = ChatOpenAI(model=\"gpt-4o\")\n",
    "llm_with_tools = llm.bind_tools(tools)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "a9092b40-20c4-4872-b0ed-be1b53a15ef3",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langgraph.graph import MessagesState\n",
    "from langchain_core.messages import HumanMessage, SystemMessage\n",
    "\n",
    "# System message\n",
    "sys_msg = SystemMessage(content=\"You are a helpful assistant tasked with performing arithmetic on a set of inputs.\")\n",
    "\n",
    "# Node\n",
    "def assistant(state: MessagesState):\n",
    "   return {\"messages\": [llm_with_tools.invoke([sys_msg] + state[\"messages\"])]}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "771123a3-91ac-4076-92c0-93bcd69cf048",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/jpeg": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from langgraph.graph import START, StateGraph\n",
    "from langgraph.prebuilt import tools_condition, ToolNode\n",
    "from IPython.display import Image, display\n",
    "\n",
    "# Graph\n",
    "builder = StateGraph(MessagesState)\n",
    "\n",
    "# Define nodes: these do the work\n",
    "builder.add_node(\"assistant\", assistant)\n",
    "builder.add_node(\"tools\", ToolNode(tools))\n",
    "\n",
    "# Define edges: these determine how the control flow moves\n",
    "builder.add_edge(START, \"assistant\")\n",
    "builder.add_conditional_edges(\n",
    "    \"assistant\",\n",
    "    # If the latest message (result) from assistant is a tool call -> tools_condition routes to tools\n",
    "    # If the latest message (result) from assistant is a not a tool call -> tools_condition routes to END\n",
    "    tools_condition,\n",
    ")\n",
    "builder.add_edge(\"tools\", \"assistant\")\n",
    "react_graph = builder.compile()\n",
    "\n",
    "# Show\n",
    "display(Image(react_graph.get_graph(xray=True).draw_mermaid_png()))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e830b7ae-3673-4cc6-8627-4740b7b8b217",
   "metadata": {},
   "source": [
    "## Memory\n",
    "\n",
    "Let's run our agent, as before."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "596a71a0-1337-44d4-971d-f80c367bd868",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================\u001b[1m Human Message \u001b[0m=================================\n",
      "\n",
      "Add 3 and 4.\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "Tool Calls:\n",
      "  add (call_zZ4JPASfUinchT8wOqg9hCZO)\n",
      " Call ID: call_zZ4JPASfUinchT8wOqg9hCZO\n",
      "  Args:\n",
      "    a: 3\n",
      "    b: 4\n",
      "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
      "Name: add\n",
      "\n",
      "7\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "\n",
      "The sum of 3 and 4 is 7.\n"
     ]
    }
   ],
   "source": [
    "messages = [HumanMessage(content=\"Add 3 and 4.\")]\n",
    "messages = react_graph.invoke({\"messages\": messages})\n",
    "for m in messages['messages']:\n",
    "    m.pretty_print()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "92f8128c-f4a5-4dee-b20b-3245bd33f6b3",
   "metadata": {},
   "source": [
    "Now, let's multiply by 2!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "b41cc1d7-e6de-4d86-8958-8cf7446f4c22",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================\u001b[1m Human Message \u001b[0m=================================\n",
      "\n",
      "Multiply that by 2.\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "Tool Calls:\n",
      "  multiply (call_prnkuG7OYQtbrtVQmH2d3Nl7)\n",
      " Call ID: call_prnkuG7OYQtbrtVQmH2d3Nl7\n",
      "  Args:\n",
      "    a: 2\n",
      "    b: 2\n",
      "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
      "Name: multiply\n",
      "\n",
      "4\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "\n",
      "The result of multiplying 2 by 2 is 4.\n"
     ]
    }
   ],
   "source": [
    "messages = [HumanMessage(content=\"Multiply that by 2.\")]\n",
    "messages = react_graph.invoke({\"messages\": messages})\n",
    "for m in messages['messages']:\n",
    "    m.pretty_print()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "26e65f3c-e1dc-4a62-b8ab-02b33a6ff268",
   "metadata": {},
   "source": [
    "We don't retain memory of 7 from our initial chat!\n",
    "\n",
    "This is because [state is transient](https://github.com/langchain-ai/langgraph/discussions/352#discussioncomment-9291220) to a single graph execution.\n",
    "\n",
    "Of course, this limits our ability to have multi-turn conversations with interruptions. \n",
    "\n",
    "We can use [persistence](https://langchain-ai.github.io/langgraph/how-tos/persistence/) to address this! \n",
    "\n",
    "LangGraph can use a checkpointer to automatically save the graph state after each step.\n",
    "\n",
    "This built-in persistence layer gives us memory, allowing LangGraph to pick up from the last state update. \n",
    "\n",
    "One of the easiest checkpointers to use is the `MemorySaver`, an in-memory key-value store for Graph state.\n",
    "\n",
    "All we need to do is simply compile the graph with a checkpointer, and our graph has memory!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "637fcd79-3896-42e4-9131-e03b123a0a90",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langgraph.checkpoint.memory import MemorySaver\n",
    "memory = MemorySaver()\n",
    "react_graph_memory = builder.compile(checkpointer=memory)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "ff8fc3bf-3999-47cb-af34-06b2b94d7192",
   "metadata": {},
   "source": [
    "When we use memory, we need to specify a `thread_id`.\n",
    "\n",
    "This `thread_id` will store our collection of graph states.\n",
    "\n",
    "Here is a cartoon:\n",
    "\n",
    "* The checkpointer write the state at every step of the graph\n",
    "* These checkpoints are saved in a thread \n",
    "* We can access that thread in the future using the `thread_id`\n",
    "\n",
    "![state.jpg](https://cdn.prod.website-files.com/65b8cd72835ceeacd4449a53/66e0e9f526b41a4ed9e2d28b_agent-memory2.png)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "f722a1d6-e73c-4023-86ed-8b07d392278d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================\u001b[1m Human Message \u001b[0m=================================\n",
      "\n",
      "Add 3 and 4.\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "Tool Calls:\n",
      "  add (call_MSupVAgej4PShIZs7NXOE6En)\n",
      " Call ID: call_MSupVAgej4PShIZs7NXOE6En\n",
      "  Args:\n",
      "    a: 3\n",
      "    b: 4\n",
      "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
      "Name: add\n",
      "\n",
      "7\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "\n",
      "The sum of 3 and 4 is 7.\n"
     ]
    }
   ],
   "source": [
    "# Specify a thread\n",
    "config = {\"configurable\": {\"thread_id\": \"1\"}}\n",
    "\n",
    "# Specify an input\n",
    "messages = [HumanMessage(content=\"Add 3 and 4.\")]\n",
    "\n",
    "# Run\n",
    "messages = react_graph_memory.invoke({\"messages\": messages},config)\n",
    "for m in messages['messages']:\n",
    "    m.pretty_print()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c91a8a16-6bf1-48e2-a889-ae04a37c7a2b",
   "metadata": {},
   "source": [
    "If we pass the same `thread_id`, then we can proceed from from the previously logged state checkpoint! \n",
    "\n",
    "In this case, the above conversation is captured in the thread.\n",
    "\n",
    "The `HumanMessage` we pass (`\"Multiply that by 2.\"`) is appended to the above conversation.\n",
    "\n",
    "So, the model now know that `that` refers to the `The sum of 3 and 4 is 7.`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "ee38c6ef-8bfb-4c66-9214-6f474c9b8451",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================\u001b[1m Human Message \u001b[0m=================================\n",
      "\n",
      "Add 3 and 4.\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "Tool Calls:\n",
      "  add (call_MSupVAgej4PShIZs7NXOE6En)\n",
      " Call ID: call_MSupVAgej4PShIZs7NXOE6En\n",
      "  Args:\n",
      "    a: 3\n",
      "    b: 4\n",
      "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
      "Name: add\n",
      "\n",
      "7\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "\n",
      "The sum of 3 and 4 is 7.\n",
      "================================\u001b[1m Human Message \u001b[0m=================================\n",
      "\n",
      "Multiply that by 2.\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "Tool Calls:\n",
      "  multiply (call_fWN7lnSZZm82tAg7RGeuWusO)\n",
      " Call ID: call_fWN7lnSZZm82tAg7RGeuWusO\n",
      "  Args:\n",
      "    a: 7\n",
      "    b: 2\n",
      "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
      "Name: multiply\n",
      "\n",
      "14\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "\n",
      "The result of multiplying 7 by 2 is 14.\n"
     ]
    }
   ],
   "source": [
    "messages = [HumanMessage(content=\"Multiply that by 2.\")]\n",
    "messages = react_graph_memory.invoke({\"messages\": messages}, config)\n",
    "for m in messages['messages']:\n",
    "    m.pretty_print()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c4b7774e-566f-4c92-9429-ed953bcacaa5",
   "metadata": {},
   "source": [
    "## LangGraph Studio\n",
    "\n",
    "\n",
    "**⚠️ DISCLAIMER**\n",
    "\n",
    "Since the filming of these videos, we've updated Studio so that it can be run locally and opened in your browser. This is now the preferred way to run Studio (rather than using the Desktop App as shown in the video). See documentation [here](https://langchain-ai.github.io/langgraph/concepts/langgraph_studio/#local-development-server) on the local development server and [here](https://langchain-ai.github.io/langgraph/how-tos/local-studio/#run-the-development-server). To start the local development server, run the following command in your terminal in the `module-1/studio/` directory in this module:\n",
    "\n",
    "```\n",
    "langgraph dev\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6d72986c-ff6f-4f81-b585-d268e2710e53",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
